Smart Contract Integration
This guide aims to help developers integrate their Solidity-based smart contracts with the existing Euclid contract set. Whether you're building on top of Euclid's infrastructure or simply interacting with it, this guide provides the necessary tools, patterns, and examples to get started.
Executing on a Euclid Contract
Each Euclid contract exposes a set of public functions. These are callable from external smart contracts using standard Solidity interface
definitions.
Pattern
To execute a function on another contract (like the Factory), you:
- Import or define the contract interface with the function you want to call.
- Pass in the correct parameters from your own contract.
- Call the function like any normal Solidity external call.
Example
Let’s say Contract A wants to perform a swap by calling the swap_request
function on the Euclid Factory.
1. Define the interface
First, define the interface for the Factory contract’s swap_request function:
interface IFactory {
function swap_request(
string calldata asset_in,
uint256 amount_in,
string calldata asset_out,
uint256 min_amount_out,
uint64 timeout,
NextSwapPair[] calldata swaps,
CrossChainUserWithLimit[] calldata cross_chain_addresses,
PartnerFee calldata partner_fee,
string calldata meta
) external;
}
2. Import the necessary structs
Solidity doesn’t automatically share structs across contracts. You must define or import them yourself.
struct NextSwapPair {
string token_in;
string token_out;
}
struct PartnerFee {
uint64 partner_fee_bps;
address recipient;
}
struct CrossChainUser {
string chain_uid;
string user_address;
}
struct CrossChainUserWithLimit {
CrossChainUser user;
uint256 limit;
}
You can copy these into your contract from the main factory. Then, prepare the data to pass into your call:
// Define the swap path (e.g., USDC → WETH → DAI)
NextSwapPair ;
swaps[0] = NextSwapPair("usdc", "weth");
swaps[1] = NextSwapPair("weth", "dai");
// Optional: Cross-chain recipient
CrossChainUserWithLimit ;
crossChainRecipients[0] = CrossChainUserWithLimit({
user: CrossChainUser("arbitrum", "0xabc123..."),
limit: 800000
});
// Optional: Partner fee config
PartnerFee memory partnerFee = PartnerFee({
partner_fee_bps: 25,
recipient: 0x1234567890abcdef1234567890abcdef12345678
});
3. Call the contract in your own function
Here factoryAddr
is the address of the deployed Factory contract you're calling.
A. Native Token Example
function performNativeSwap(address factoryAddr) external payable {
IFactory(factoryAddr).swap_request{value: msg.value}(
"eth",
msg.value,
"dai",
980000,
60,
swaps,
crossChainRecipients,
partnerFee,
"eth-to-dai"
);
}
B. ERC20 Token Example
function performSwap(address factoryAddr) external {
IFactory(factoryAddr).swap_request(
"usdc",
1000000,
"dai",
980000,
60,
swaps,
crossChainRecipients,
partnerFee,
"custom-metadata"
);
}
Querying a Euclid Contract
In Solidity, queries are simply view
functions. To call them from another contract:
- Define the interface with the correct function signatures.
- Call them directly via the contract address.
Example
Let’s say Contract A wants to check whether a specific token is allowed in a given Escrow contract.
1. Define the interface
interface IEscrow {
function isTokenAllowed(TokenType calldata tokenInfo) external view returns (bool);
}
2. Define the struct
struct TokenType {
uint8 tokenType; // 0 = Native, 1 = Smart, 2 = Voucher
string denom;
address contractAddress;
}
3. Perform the query
function checkTokenAllowed(address escrowAddr) external view returns (bool) {
TokenType memory tokenInfo = TokenType({
tokenType: 0,
denom: "usdc",
contractAddress: address(0)
});
return IEscrow(escrowAddr).isTokenAllowed(tokenInfo);
}